package com.seven.smartsnmp.handler;

import com.seven.smartsnmp.base.MyException;
import com.seven.smartsnmp.base.OMMappingInfo;
import com.seven.smartsnmp.snmp.SNMPAPI;
import com.seven.smartsnmp.snmp.SNMPFactory;
import com.seven.smartsnmp.utils.SNMPUtils;
import net.percederberg.mibble.MibValueSymbol;
import org.apache.log4j.Logger;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.Target;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.Variable;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.util.DefaultPDUFactory;
import org.snmp4j.util.TableEvent;
import org.snmp4j.util.TableUtils;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * @author Admin
 */

public class SelectHandler {

    private static final Logger log = Logger.getLogger(SelectHandler.class);

    /**
     * @param snmp
     * @param target
     * @param clazz
     * @return
     * @throws MyException
     */
    public List getAllTableData(Snmp snmp, Target target, Class clazz) throws MyException {

        try {
            //获取对象oid
            String mappingOID = SNMPUtils.getMibOIDofClass(clazz);
            //获取mib值相关数据
            MibValueSymbol mibValueSymbol = SNMPFactory.getInstance().getMibSymbolByOid(mappingOID);
            //获取对象字段对应的oid
            List<OID> oidList = getFieldsInMibOID(clazz, mibValueSymbol);
            //获表的全部信息
            TableUtils tableUtils = new TableUtils(snmp, new DefaultPDUFactory());
            List<TableEvent> tableEvents = tableUtils.getTable(target, oidList.toArray(new OID[oidList.size()]), (OID) null, (OID) null);
            //判断信息的状态
            List<TableEvent> eventList = getEventListStatus(mappingOID, tableEvents);
            //表数据转换成对象
            List ObjectList = mibTableToObject(clazz, mibValueSymbol, eventList);
            return ObjectList;
        } catch (Exception exception) {
            log.error(exception.toString());
            throw new MyException(target.getAddress() + ":获取表格出错");
        }
    }

    public List<List<String>> getAllOIDTableData(Snmp snmp, Target target, List<String> list) throws MyException {
        try {
            List<List<String>> retList = new ArrayList<>();
            OID[] oids = new OID[list.size()];
            for (int i = 0; i < list.size(); ++i) {
                String oid = (String) list.get(i);
                oids[i] = new OID(oid);
            }
            List<TableEvent> eventLists = new ArrayList<>();
            TableUtils tableUtils = new TableUtils(snmp, new DefaultPDUFactory());
            List eventList = tableUtils.getTable(target, oids, (OID) null, (OID) null);


            for (int i = 0; i < eventList.size(); i++) {
                TableEvent event = (TableEvent) eventList.get(i);
                if (event.isError()) {
                    throw new MyException("获取snmp表出错：" + event.getErrorMessage());
                }
                if (event.getException() != null) {
                    throw new MyException("获取snmp表出现异常：" + event.getErrorMessage() + "," + event.getException().getMessage());
                }

                if (event.getStatus() != 0) {
                    throw new MyException("获取snmp表出错：" + event.getErrorMessage());
                }
                if (event.getColumns() != null && event.getColumns().length >= 1) {
                    eventLists.add(event);
                }
            }
            for (int i = 0; i < eventLists.size(); i++) {
                List<String> valueList = new ArrayList<>();
                TableEvent event = (TableEvent) eventLists.get(i);
                String str = event.getIndex().toString();
                valueList.add(str);
                VariableBinding[] variableBindings = event.getColumns();
                for (int j = 0; j < variableBindings.length; ++j) {
                    try {
                        VariableBinding variableBinding = variableBindings[i];
                        if (variableBinding != null) {
                            Variable variable = variableBinding.getVariable();
                            valueList.add(variable.toString());
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                retList.add(valueList);
            }

            return retList;
        } catch (Exception e) {
            String msg = "从设备中获取表的多个oid数据出差，设备ip:" + target.getAddress() + ",错误:" + e.getMessage();
            throw new MyException(msg);
        }

    }

    /**
     * 获取下一个节点的数据
     *
     * @param oid
     * @param snmp
     * @param target
     * @return
     * @throws MyException
     */
    public Variable getNextValue(String oid, Snmp snmp, Target target) throws MyException {
        try {
            PDU pdu = SNMPUtils.createPdu(target.getVersion());
            pdu.add(new VariableBinding(new OID(oid)));
            ResponseEvent event = snmp.getNext(pdu, target);
            SNMPUtils.checkSNMPErro(event);
            PDU resPdu = event.getResponse();
            VariableBinding variableBinding = resPdu.get(0);
            Variable variable = variableBinding.getVariable();
            String varStr = variable.toString(); snmp.close();
            if (!varStr.equalsIgnoreCase("noSuchInstance") && !varStr.equalsIgnoreCase("No such name") && !varStr.equalsIgnoreCase("noSuchObject")) {
                return variable;
            } else {
                throw new MyException(SNMPAPI.MessageNoSuchOID);
            }

        } catch (Exception e) {
            String var4 = "获取下一个oid的值出错(" + oid + "),错误:" + e.getMessage();
            throw new MyException(var4);
        }
    }

    /**
     * 获取当前节点
     *
     * @param oid
     * @param snmp
     * @param target
     * @return
     * @throws MyException
     */
    public Variable getValue(String oid, Snmp snmp, Target target) throws MyException {
        try {
            PDU pdu = SNMPUtils.createPdu(target.getVersion());
            pdu.add(new VariableBinding(new OID(oid)));
            ResponseEvent event = snmp.get(pdu, target);
            SNMPUtils.checkSNMPErro(event);
            PDU resEvent = event.getResponse();
            VariableBinding variableBinding = resEvent.get(0);
            Variable variable = variableBinding.getVariable();
            String varStr = variable.toString();
            if (!varStr.equalsIgnoreCase("noSuchInstance") &&
                    !varStr.equalsIgnoreCase("No such name")
                    && !varStr.equalsIgnoreCase("noSuchObject")) {
                return variable;
            } else {
                return null;
            }
        } catch (Exception e) {
            String msg = "获取OID的值出错(" + oid + "),错误:" + e.getMessage();
            throw new MyException(msg);
        }

    }


    /**
     * 获取到的数据转换到对象中去
     *
     * @param clazz
     * @param mibValueSymbol
     * @param eventList
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    private List mibTableToObject(Class clazz, MibValueSymbol mibValueSymbol, List<TableEvent> eventList) throws InstantiationException, IllegalAccessException {
        List list = new ArrayList();
        for (int i = 0; i < eventList.size(); i++) {
            Object object = clazz.newInstance();
            list.add(object);
            TableEvent event = eventList.get(i);
            if (object instanceof OMMappingInfo) {
                ((OMMappingInfo) object).setTableIndexOID(event.getIndex().toString());
            }
            VariableBinding[] variableBindings = event.getColumns();
            for (int j = 0; j < variableBindings.length; j++) {
                VariableBinding variableBinding = variableBindings[j];
                if (variableBinding != null) {
                    String oid = variableBinding.getOid().toString();
                    String name = mibValueSymbol.getMib().getSymbolByOid(oid).getName();
                    Variable variable = variableBinding.getVariable();
                    SNMPUtils.setFieldValue(object, name, variable);
                }
            }
        }
        return list;
    }

    /**
     * 获取表格全部数据
     *
     * @param mappingOID
     * @param tableEvents
     * @return
     * @throws MyException
     */
    private List<TableEvent> getEventListStatus(String mappingOID, List<TableEvent> tableEvents) throws MyException {
        List eventList = new ArrayList();
        Iterator<TableEvent> it = tableEvents.iterator();
        while (it.hasNext()) {
            TableEvent tableEvent = it.next();
            if (tableEvent.isError()) {
                System.out.println(tableEvent.getException());
                log.error(mappingOID + ":获取表格出现异常");
                throw new MyException(mappingOID + ":获取表格错误");
            }
            if (tableEvent.getException() != null) {
                System.out.println(tableEvent.getException());
                log.error(mappingOID + ":获取表格出现异常");
                throw new MyException(mappingOID + "获取表格出现异常");
            }
            if (tableEvent.getStatus() != 0) {
                System.out.println(tableEvent.getException());
                log.error(mappingOID + "获取表格状态错误");
                throw new MyException(mappingOID + "状态错误");
            }
            if (tableEvent.getColumns() != null && tableEvent.getColumns().length >= 1) {
                eventList.add(tableEvent);
            }
        }
        return eventList;
    }

    /**
     * 根据class获取类全部的oid信息
     *
     * @param clazz
     * @return
     * @throws Exception
     */
    private List<OID> getFieldsInMibOID(Class clazz, MibValueSymbol mibValueSymbol) throws Exception {


        List<MibValueSymbol> fieldsMib = SNMPUtils.getFieldsInMibNodeNew(clazz, mibValueSymbol);

        List<OID> oidList = new ArrayList<>();
        for (MibValueSymbol symbol : fieldsMib) {
            String oid = symbol.getValue().toString();
            oidList.add(new OID(oid));
        }
        return oidList;
    }


}
